#pragma once
#include "const.hpp"
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/system/error_code.hpp>
#include <cstddef>
#include <functional>
#include <memory>
#include <queue>
class CServer;
struct MessageNode {
  char _data[MAX_LENGTH + 1];
  unsigned short _msg_len;
  unsigned short _msg_id;
  MessageNode() = default;
  MessageNode(unsigned short msg_id, unsigned short msg_len, const char *data);
};

class CSession : public std::enable_shared_from_this<CSession> {

public:
  CSession(boost::asio::io_context &io_context, CServer *server);
  ~CSession();
  boost::asio::ip::tcp::socket &GetSocket();
  std::string &GetSessionId();
  void SetUserId(int uid);
  int GetUserId();
  void Start();
  void AsyncReadHead(int head_total_len);
  void Send(const char *msg, unsigned short msg_len, unsigned short msg_id);
  void asyncReadFull(std::size_t maxlength,
                     std::function<void(const boost::system::error_code &ec,
                                        std::size_t bytes_transfered)>
                         handler);
  void asyncReadLen(std::size_t read_len, std::size_t total_len,
                    std::function<void(const boost::system::error_code &ec,
                                       std::size_t bytes_transfered)>
                        handler);
  void AsyncReadBody(int total_len);
  void Close();
  void HandleWrite(std::shared_ptr<CSession> self,
                   const boost::system::error_code &ec,
                   std::size_t bytes_transferred);

private:
  boost::asio::ip::tcp::socket _socket;
  std::string _sessionId;
  int _userId;
  CServer *_server;
  bool _b_close;
  bool _b_head_parse;
  std::shared_ptr<MessageNode> _recv_head_node;
  std::mutex _send_mutex;
  std::queue<std::shared_ptr<MessageNode>> _send_que;
  char _data[MAX_LENGTH + 1];
};